/**
给你一个整数数组 nums ，判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ，同时还满足 nums[i] + nums[j] + nums[k] == 0 。
请你返回所有和为 0 且不重复的三元组。

注意：答案中不可以包含重复的三元组。

示例 1：
输入：nums = [-1,0,1,2,-1,-4]
输出：[[-1,-1,2],[-1,0,1]]
解释：
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意，输出的顺序和三元组的顺序并不重要。

示例 2：
输入：nums = [0,1,1]
输出：[]
解释：唯一可能的三元组和不为 0 。

示例 3：
输入：nums = [0,0,0]
输出：[[0,0,0]]
解释：唯一可能的三元组和为 0 。

3 <= nums.length <= 3000
-10^5 <= nums[i] <= 10^5

 */
/**
 *
 * @param {*} nums
 *
 */
var threeSum = function (nums) {
  nums.sort((a, b) => a - b);

  let ans = [],
    n = nums.length;
  for (let i = 0; i < n - 2; i++) {
    let x = nums[i];
    if (i > 0 && x == nums[i - 1]) {
      continue;
    }
    // 优化，如果x和最小的2个数加起来都大于0，那么整体肯定大于0,因为三者的和肯定越来越大
    if (x + nums[i + 1] + nums[i + 2] > 0) {
      break;
    }
    // 如果x和最大的2个数加起来小于0，就跳过当前数，下一个
    if (x + nums[n - 1] + nums[n - 2] < 0) {
      continue;
    }

    let j = i + 1,
      k = n - 1;

    while (j < k) {
      let sum = x + nums[j] + nums[k];
      if (sum > 0) {
        k--;
      } else if (sum < 0) {
        j++;
      } else {
        ans.push([x, nums[j], nums[k]]);
        j++;
        while (j < k && nums[j] === nums[j - 1]) {
          j++;
          k++;
        }
        while (k > j && nums[k] === nums[k + 1]) {
          k--;
        }
      }
    }
  }
  return ans;
};

export default threeSum;
console.log(threeSum([-1, 0, 1, 2, -1, -4]));
